package com.loveyukari.douyu.client;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.loveyukari.common.exception.InternalException;
import com.loveyukari.douyu.utils.FormatTransfer;
import com.loveyukari.utils.HttpUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.loveyukari.douyu.MessageService;
import com.loveyukari.douyu.utils.DouyuMessageUtil;

import net.sf.json.JSONObject;

/**
*
*yangshaohua
*2016年12月8日下午2:08:17
**/
public class DouyuClient {

	private static Logger log = LoggerFactory.getLogger("DouyuClient");
	private static Logger debugLog = LoggerFactory.getLogger("DebugLog");
	
	//第三方弹幕协议服务器地址
	private String hostName;
	
	//第三方弹幕协议服务器端口
	private static final int port = 8601;
	
	//设置字节获取buffer的最大值
    private static final int MAX_BUFFER_LENGTH = 81920;
	
	  //socket相关配置
    private Socket sock;
    private BufferedOutputStream bos;
    private BufferedInputStream bis;
    
    private boolean readyFlag = false;
    private boolean initFlag = true;

	public boolean isReadyFlag() {
		return readyFlag;
	}

	private int roomId;
	public int getRoomId() {
		return roomId;
	}

	private int groupId = -9999;

	public boolean init(){
		log.info("info client room: "+roomId);
		int count = 0;
		while (true) {
			count++;
			try {
				if (!initFlag || count >= 3) {
					return false;
				}
				String host = InetAddress.getByName(hostName).getHostAddress();
				log.info("info client host: "+host);
				//建立socke连接
				sock = new Socket(host, port);
				//设置socket输入及输出
				bos = new BufferedOutputStream(sock.getOutputStream());
				bis = new BufferedInputStream(sock.getInputStream());

				Map<String, Object> loginParam = new HashMap<String, Object>();
				loginParam.put("type", "loginreq");
				loginParam.put("roomid", roomId);
				byte[] loginRequestData = DouyuMessageUtil.getRequestData(loginParam);
				bos.write(loginRequestData, 0, loginRequestData.length);
				bos.flush();

				Map<String, Object> groupParam = new HashMap<String, Object>();
				groupParam.put("type", "joingroup");
				groupParam.put("rid", roomId);
				groupParam.put("gid", groupId);
				byte[] groupRequestData = DouyuMessageUtil.getRequestData(groupParam);
				bos.write(groupRequestData, 0, groupRequestData.length);
				bos.flush();
				this.readyFlag = true;
				return true;
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e1) {
				}
			}
		}
	}

	public void sendMsg(Map<String, Object> map) throws IOException {
		byte[] bs = DouyuMessageUtil.getRequestData(map);
		bos.write(bs, 0, bs.length);
		bos.flush();
	}
	
	public void start(){
		KeepLiveThread keepLiveThread = new KeepLiveThread();
		keepLiveThread.start();
		ServerMessageThread messageThread = new ServerMessageThread();
		messageThread.start();
	}
	
	public void keepLive() throws IOException{
		log.info("keep live room: "+roomId);
		Map<String, Object> keepParam = new HashMap<String,Object>();
		keepParam.put("type", "keeplive");
		keepParam.put("tick", (int)System.currentTimeMillis()/1000);
		byte[] keepReauestData = DouyuMessageUtil.getRequestData(keepParam);
		bos.write(keepReauestData, 0, keepReauestData.length);
		bos.flush();
	}
	
	
	private MessageService[] messageServices;
	
	
	public DouyuClient(int roomId,String server,MessageService... messageService) {
		super();
		this.hostName = server;
		this.roomId = roomId;
		this.messageServices = messageService;
	}

	private static final int readMax = 65535;
	private static final String splitStr = "type@=";
	private byte[] bs = new byte[readMax];
	private StringBuilder messages = new StringBuilder();
	public void getServerMessage() {
		try {
			int l = bis.read(bs);
			messages.append(new String(bs, 0, l));
			do {
				int start = messages.indexOf(splitStr);
				if (start == -1) {
					break;
				}
				int end = messages.indexOf(splitStr, start + 1);
				if (end == -1) {
					if (messages.charAt(messages.length() - 1) == '\u0000') {
						end = messages.length();
					} else {
						break;
					}
				}
				String message = messages.substring(start, end);
				message = message.substring(0, message.lastIndexOf("/"));
				messages.delete(0, end);
				dataStrWork(message);
			} while (true);
		} catch (SocketException e){
			close();
			log.error(e.getMessage(),e);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}

	}

	private void dataStrWork(String dataStr){
		if(StringUtils.startsWith(dataStr,"type@=pendant")){
			System.out.println(dataStr);
		}
		debugLog.info(dataStr);
		JSONObject result = DouyuMessageUtil.parseDataJsonObject(dataStr);
		String type = result.optString("type");
		if (checkType(type)){
			MessageService[] mss = this.messageServices;
			for (int i = 0; i < mss.length; i++) {
				try {
					MessageService messageService = mss[i];
					messageService.messageWork(result);
				} catch (Exception e) {
					JSONObject errorInfo = new JSONObject();
					errorInfo.put("dataStr",dataStr);
					errorInfo.put("dataJson",result);
					log.error(errorInfo.toString(),e);
				}
			}
		}
		
	}
	
	class KeepLiveThread extends Thread{

		@Override
		public void run() {
			while (readyFlag){
				try {
					keepLive();
					Thread.sleep(45000);
				} catch (Exception e) {
					log.error(e.getMessage(),e);
					close();
				}
			}
		}
	}
	private int errorCount = 0;
	class ServerMessageThread extends Thread{
		@Override
		public void run() {
			while(readyFlag){
				try {
					getServerMessage();
					errorCount = 0;
				} catch (Exception e) {
					log.error(e.getMessage(), e);
					errorCount++;
					if (errorCount >= 5){
						close();
					}
				}
			}
			close();
		}
	}

	public void close(){
		this.readyFlag = false;
		this.initFlag = false;
		try {
			if (bos != null){
				bos.close();
			}
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
		try {
			if (bis != null){
				bis.close();
			}
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
		try {
			if (sock != null){
				sock.close();
			}
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
	}
	
	private final static Set<String> DIS_TYPE_SET = new HashSet<String>();
	static {
		DIS_TYPE_SET.add("online_noble_list");//贵族
//		DIS_TYPE_SET.add("keeplive");//心跳
		DIS_TYPE_SET.add("ul_ranklist");//等级排行榜
//		DIS_TYPE_SET.add("ranklist");//日、周、总榜排名，crk为排序
//		DIS_TYPE_SET.add("spbc");//礼物广播
//		DIS_TYPE_SET.add("rlcn");//分区房间排名
		DIS_TYPE_SET.add("gpbc");//飞机礼物领取
		DIS_TYPE_SET.add("ggbb");//火箭鱼丸领取
//		DIS_TYPE_SET.add("ssd");//超级弹幕
		DIS_TYPE_SET.add("newblackres");//禁言操作结果
		DIS_TYPE_SET.add("onlinegift");//在线领取鱼丸
//		DIS_TYPE_SET.add("gbroadcast");//广播，贵族喇叭？
//		DIS_TYPE_SET.add("rsm");//弹窗式通知
//		DIS_TYPE_SET.add("0");//弹窗式通知链接
		DIS_TYPE_SET.add("6");//未知
		DIS_TYPE_SET.add("srres");//用户分享直播间
		DIS_TYPE_SET.add("qausrespond");//未知
		DIS_TYPE_SET.add("upbc");//主播升级
		DIS_TYPE_SET.add("synexp");//主播经验
		DIS_TYPE_SET.add("frank");//粉丝排名
		DIS_TYPE_SET.add("upgrade");//用户升级
		DIS_TYPE_SET.add("blab");//粉丝牌子升级
	}
	private boolean checkType(String str){
		if (StringUtils.isBlank(str)){
			return false;
		}
		for (String type : DIS_TYPE_SET) {
			if (str.startsWith(type)){
				return false;
			}
		}
		return true;
	}



}
